package com.processmanager.sdk;

import com.processmanager.sdk.enums.ProcessStatus;
import com.processmanager.sdk.model.ProcessInfo;
import com.processmanager.sdk.model.ProcessLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.Consumer;

/**
 * 进程管理器SDK
 * 
 * <p>提供进程生命周期管理的核心功能：</p>
 * <ul>
 *   <li>异步执行命令行命令</li>
 *   <li>实时监控进程状态</li>
 *   <li>收集进程输出日志</li>
 *   <li>支持进程停止控制</li>
 *   <li>线程安全的进程管理</li>
 * </ul>
 * 
 * <p>使用示例：</p>
 * <pre>{@code
 * ProcessManager manager = new ProcessManager();
 * 
 * // 执行命令
 * String processId = manager.executeCommand("ffmpeg -i input.mp4 output.mp4", "FFmpeg转换");
 * 
 * // 获取进程信息
 * ProcessInfo info = manager.getProcessInfo(processId);
 * 
 * // 停止进程
 * manager.stopProcess(processId);
 * }</pre>
 * 
 * @author ProcessManager
 * @version 1.0.0
 * @since 2024-01-01
 */
public class ProcessManager {
    
    private static final Logger logger = LoggerFactory.getLogger(ProcessManager.class);
    
    /**
     * 进程信息存储（线程安全）
     */
    private final Map<String, ProcessInfo> processes = new ConcurrentHashMap<>();
    
    /**
     * 进程任务存储（线程安全）
     */
    private final Map<String, Future<?>> processTasks = new ConcurrentHashMap<>();
    
    /**
     * 线程池执行器
     */
    private final ExecutorService executorService;
    
    /**
     * 日志回调函数
     */
    private Consumer<ProcessLog> logCallback;
    
    /**
     * 默认构造函数，使用可缓存线程池
     */
    public ProcessManager() {
        this(Executors.newCachedThreadPool());
    }
    
    /**
     * 带线程池的构造函数
     * 
     * @param executorService 线程池执行器
     */
    public ProcessManager(ExecutorService executorService) {
        this.executorService = executorService;
    }
    
    /**
     * 执行命令行命令
     * 
     * <p>异步执行指定的命令，返回进程ID用于后续管理。命令将在后台运行，
     * 进程状态和日志会被实时监控和收集。</p>
     * 
     * @param command 要执行的命令
     * @param name 进程名称
     * @return 进程唯一标识
     * @throws IllegalArgumentException 如果命令为空或无效
     */
    public String executeCommand(String command, String name) {
        if (command == null || command.trim().isEmpty()) {
            throw new IllegalArgumentException("命令不能为空");
        }
        
        String processId = UUID.randomUUID().toString();
        ProcessInfo processInfo = new ProcessInfo(processId, name, command);
        processes.put(processId, processInfo);
        
        logger.info("开始执行命令: {} (进程ID: {})", command, processId);
        
        Future<?> task = executorService.submit(() -> {
            try {
                executeProcess(processInfo);
            } catch (Exception e) {
                logger.error("进程执行异常: {}", e.getMessage(), e);
                processInfo.setStatus(ProcessStatus.ERROR);
                processInfo.setErrorMessage(e.getMessage());
                addSystemLog(processInfo, "进程执行异常: " + e.getMessage(), ProcessLog.LogLevel.ERROR);
            }
        });
        
        processTasks.put(processId, task);
        return processId;
    }
    
    /**
     * 获取进程信息
     * 
     * @param processId 进程ID
     * @return 进程信息，如果不存在则返回null
     */
    public ProcessInfo getProcessInfo(String processId) {
        return processes.get(processId);
    }
    
    /**
     * 获取所有进程信息
     * 
     * @return 所有进程信息的副本
     */
    public Map<String, ProcessInfo> getAllProcesses() {
        return new ConcurrentHashMap<>(processes);
    }
    
    /**
     * 停止指定进程
     * 
     * <p>尝试优雅地停止进程，如果失败则强制终止。</p>
     * 
     * @param processId 进程ID
     * @return 是否成功停止
     */
    public boolean stopProcess(String processId) {
        ProcessInfo processInfo = processes.get(processId);
        if (processInfo == null) {
            logger.warn("进程不存在: {}", processId);
            return false;
        }
        
        if (processInfo.getStatus() == ProcessStatus.STOPPED) {
            logger.info("进程已经停止: {}", processId);
            return true;
        }
        
        logger.info("正在停止进程: {}", processId);
        processInfo.setStatus(ProcessStatus.STOPPING);
        
        Future<?> task = processTasks.get(processId);
        if (task != null && !task.isDone()) {
            task.cancel(true);
        }
        
        processInfo.setStatus(ProcessStatus.STOPPED);
        processInfo.setEndTime(java.time.LocalDateTime.now());
        addSystemLog(processInfo, "进程已停止", ProcessLog.LogLevel.INFO);
        
        return true;
    }
    
    /**
     * 设置日志回调函数
     * 
     * @param callback 日志回调函数
     */
    public void setLogCallback(Consumer<ProcessLog> callback) {
        this.logCallback = callback;
    }
    
    /**
     * 清理已停止的进程
     * 
     * @param maxAgeSeconds 最大保留时间（秒）
     */
    public void cleanupStoppedProcesses(long maxAgeSeconds) {
        long cutoffTime = System.currentTimeMillis() - (maxAgeSeconds * 1000);
        
        processes.entrySet().removeIf(entry -> {
            ProcessInfo info = entry.getValue();
            if (info.getStatus() == ProcessStatus.STOPPED || info.getStatus() == ProcessStatus.ERROR) {
                if (info.getEndTime() != null && 
                    info.getEndTime().atZone(java.time.ZoneId.systemDefault()).toInstant().toEpochMilli() < cutoffTime) {
                    processTasks.remove(entry.getKey());
                    logger.info("清理已停止的进程: {}", entry.getKey());
                    return true;
                }
            }
            return false;
        });
    }
    
    /**
     * 关闭进程管理器
     * 
     * <p>停止所有运行的进程并关闭线程池。</p>
     */
    public void shutdown() {
        logger.info("正在关闭进程管理器...");
        
        // 停止所有进程
        processes.keySet().forEach(this::stopProcess);
        
        // 关闭线程池
        if (executorService != null && !executorService.isShutdown()) {
            executorService.shutdown();
        }
        
        logger.info("进程管理器已关闭");
    }
    
    /**
     * 执行进程的核心方法
     * 
     * @param processInfo 进程信息
     */
    private void executeProcess(ProcessInfo processInfo) {
        Process process = null;
        try {
            // 创建进程构建器
            ProcessBuilder processBuilder = new ProcessBuilder();
            
            // 根据操作系统设置命令
            boolean isWindows = System.getProperty("os.name").toLowerCase().contains("windows");
            if (isWindows) {
                processBuilder.command("cmd", "/c", processInfo.getCommand());
            } else {
                processBuilder.command("sh", "-c", processInfo.getCommand());
            }
            
            // 合并错误流到标准输出流
            processBuilder.redirectErrorStream(true);
            
            // 启动进程
            process = processBuilder.start();
            processInfo.setStatus(ProcessStatus.RUNNING);
            addSystemLog(processInfo, "进程已启动", ProcessLog.LogLevel.INFO);
            
            // 读取进程输出，修复编码问题
            String charset = isWindows ? "GBK" : "UTF-8";
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream(), charset))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    if (Thread.currentThread().isInterrupted()) {
                        break;
                    }
                    ProcessLog log = ProcessLog.info(line, ProcessLog.LogSource.STDOUT);
                    processInfo.addLog(log);
                    if (logCallback != null) {
                        logCallback.accept(log);
                    }
                }
            }
            
            // 等待进程结束
            int exitCode = process.waitFor();
            processInfo.setExitCode(exitCode);
            processInfo.setEndTime(java.time.LocalDateTime.now());
            
            if (exitCode == 0) {
                processInfo.setStatus(ProcessStatus.STOPPED);
                addSystemLog(processInfo, "进程正常结束", ProcessLog.LogLevel.INFO);
            } else {
                processInfo.setStatus(ProcessStatus.ERROR);
                processInfo.setErrorMessage("进程异常退出，退出码: " + exitCode);
                addSystemLog(processInfo, "进程异常退出，退出码: " + exitCode, ProcessLog.LogLevel.ERROR);
            }
            
        } catch (IOException e) {
            logger.error("进程IO异常: {}", e.getMessage(), e);
            processInfo.setStatus(ProcessStatus.ERROR);
            processInfo.setErrorMessage("IO异常: " + e.getMessage());
            addSystemLog(processInfo, "IO异常: " + e.getMessage(), ProcessLog.LogLevel.ERROR);
        } catch (InterruptedException e) {
            logger.info("进程被中断: {}", processInfo.getProcessId());
            Thread.currentThread().interrupt();
            processInfo.setStatus(ProcessStatus.STOPPED);
            addSystemLog(processInfo, "进程被中断", ProcessLog.LogLevel.WARN);
        } finally {
            if (process != null) {
                process.destroy();
            }
        }
    }
    
    /**
     * 添加系统日志
     * 
     * @param processInfo 进程信息
     * @param message 日志消息
     * @param level 日志级别
     */
    private void addSystemLog(ProcessInfo processInfo, String message, ProcessLog.LogLevel level) {
        ProcessLog log = new ProcessLog(level, message, ProcessLog.LogSource.SYSTEM);
        processInfo.addLog(log);
        
        if (logCallback != null) {
            logCallback.accept(log);
        }
    }
} 